package com.rickpan.service.impl;

import com.rickpan.entity.ProjectAnnouncement;
import com.rickpan.exception.BusinessException;
import com.rickpan.repository.ProjectAnnouncementRepository;
import com.rickpan.service.ProjectAnnouncementService;
import com.rickpan.service.ProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.Optional;

/**
 * 项目公告服务实现类
 * 
 * @author RickPan Team
 * @since 2024-01-15
 */
@Service
@Transactional
public class ProjectAnnouncementServiceImpl implements ProjectAnnouncementService {

    private static final Logger logger = LoggerFactory.getLogger(ProjectAnnouncementServiceImpl.class);

    @Autowired
    private ProjectAnnouncementRepository announcementRepository;

    @Autowired
    @Lazy
    private ProjectService projectService;

    @Override
    public ProjectAnnouncement createAnnouncement(ProjectAnnouncement announcement) {
        logger.info("创建公告: {}, 项目ID: {}", announcement.getTitle(), announcement.getProjectId());

        // 检查项目中是否存在同标题公告
        if (announcementRepository.existsByProjectIdAndTitle(announcement.getProjectId(), announcement.getTitle())) {
            throw new BusinessException("项目中已存在同标题公告: " + announcement.getTitle());
        }

        // 设置初始状态
        if (announcement.getIsPinned() == null) {
            announcement.setIsPinned(false);
        }

        // 保存公告
        return announcementRepository.save(announcement);
    }

    @Override
    public ProjectAnnouncement updateAnnouncement(ProjectAnnouncement announcement) {
        logger.info("更新公告: {}, ID: {}", announcement.getTitle(), announcement.getId());

        // 检查公告是否存在
        ProjectAnnouncement existingAnnouncement = announcementRepository.findById(announcement.getId())
                .orElseThrow(() -> new BusinessException("公告不存在: " + announcement.getId()));

        // 检查项目中是否存在同标题公告（排除当前公告）
        if (!existingAnnouncement.getTitle().equals(announcement.getTitle()) &&
                announcementRepository.existsByProjectIdAndTitleExcludingId(
                        announcement.getProjectId(), announcement.getTitle(), announcement.getId())) {
            throw new BusinessException("项目中已存在同标题公告: " + announcement.getTitle());
        }

        // 更新公告
        return announcementRepository.save(announcement);
    }

    @Override
    public void deleteAnnouncement(Long announcementId) {
        logger.info("删除公告: {}", announcementId);

        // 检查公告是否存在
        if (!announcementRepository.existsById(announcementId)) {
            throw new BusinessException("公告不存在: " + announcementId);
        }

        // 删除公告
        announcementRepository.deleteById(announcementId);
    }

    @Override
    @Transactional(readOnly = true)
    public Optional<ProjectAnnouncement> findById(Long announcementId) {
        return announcementRepository.findById(announcementId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findAnnouncementsByProject(Long projectId) {
        return announcementRepository.findByProjectIdOrderByIsPinnedDescCreatedAtDesc(projectId);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<ProjectAnnouncement> findAnnouncementsByProject(Long projectId, Pageable pageable) {
        return announcementRepository.findByProjectIdOrderByIsPinnedDescCreatedAtDesc(projectId, pageable);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findPinnedAnnouncementsByProject(Long projectId) {
        return announcementRepository.findByProjectIdAndIsPinnedTrueOrderByCreatedAtDesc(projectId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findNormalAnnouncementsByProject(Long projectId) {
        return announcementRepository.findByProjectIdAndIsPinnedFalseOrderByCreatedAtDesc(projectId);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<ProjectAnnouncement> findNormalAnnouncementsByProject(Long projectId, Pageable pageable) {
        return announcementRepository.findByProjectIdAndIsPinnedFalseOrderByCreatedAtDesc(projectId, pageable);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findAnnouncementsByCreator(Long creatorId) {
        return announcementRepository.findByCreatorIdOrderByCreatedAtDesc(creatorId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> searchAnnouncements(Long projectId, String keyword) {
        return announcementRepository.searchAnnouncementsByProject(projectId, keyword);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<ProjectAnnouncement> searchAnnouncements(Long projectId, String keyword, Pageable pageable) {
        return announcementRepository.searchAnnouncementsByProject(projectId, keyword, pageable);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findAnnouncementsByDateRange(Long projectId, LocalDateTime startDate, LocalDateTime endDate) {
        return announcementRepository.findAnnouncementsByDateRange(projectId, startDate, endDate);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<ProjectAnnouncement> findAnnouncementsByDateRange(Long projectId, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
        return announcementRepository.findAnnouncementsByDateRange(projectId, startDate, endDate, pageable);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findTodayAnnouncements(Long projectId) {
        return announcementRepository.findTodayAnnouncementsByProject(projectId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findWeekAnnouncements(Long projectId) {
        LocalDateTime weekStart = LocalDateTime.now().with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY))
                .with(LocalTime.MIN);
        return announcementRepository.findWeekAnnouncementsByProject(projectId, weekStart);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ProjectAnnouncement> findMonthAnnouncements(Long projectId) {
        LocalDateTime monthStart = LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth())
                .with(LocalTime.MIN);
        return announcementRepository.findMonthAnnouncementsByProject(projectId, monthStart);
    }

    @Override
    public void pinAnnouncement(Long announcementId) {
        logger.info("置顶公告: {}", announcementId);

        // 检查公告是否存在
        ProjectAnnouncement announcement = announcementRepository.findById(announcementId)
                .orElseThrow(() -> new BusinessException("公告不存在: " + announcementId));

        // 设置置顶
        announcement.setIsPinned(true);

        // 保存公告
        announcementRepository.save(announcement);
    }

    @Override
    public void unpinAnnouncement(Long announcementId) {
        logger.info("取消置顶公告: {}", announcementId);

        // 检查公告是否存在
        ProjectAnnouncement announcement = announcementRepository.findById(announcementId)
                .orElseThrow(() -> new BusinessException("公告不存在: " + announcementId));

        // 取消置顶
        announcement.setIsPinned(false);

        // 保存公告
        announcementRepository.save(announcement);
    }

    @Override
    @Transactional(readOnly = true)
    public AnnouncementStatistics getAnnouncementStatistics(Long projectId) {
        // 获取公告总数
        long totalAnnouncements = announcementRepository.countByProjectId(projectId);
        
        // 获取置顶公告数
        long pinnedAnnouncements = announcementRepository.countByProjectIdAndIsPinnedTrue(projectId);
        
        // 获取今日公告数
        long todayAnnouncements = findTodayAnnouncements(projectId).size();
        
        // 获取本周公告数
        long weekAnnouncements = findWeekAnnouncements(projectId).size();
        
        // 获取本月公告数
        long monthAnnouncements = findMonthAnnouncements(projectId).size();
        
        return new AnnouncementStatistics(totalAnnouncements, pinnedAnnouncements, 
                                        todayAnnouncements, weekAnnouncements, monthAnnouncements);
    }

    @Override
    @Transactional(readOnly = true)
    public boolean hasAnnouncementManagePermission(Long announcementId, Long userId) {
        // 检查公告是否存在
        ProjectAnnouncement announcement = announcementRepository.findById(announcementId)
                .orElseThrow(() -> new BusinessException("公告不存在: " + announcementId));
        
        // 检查用户是否是公告创建者
        if (announcement.getCreatorId().equals(userId)) {
            return true;
        }
        
        // 检查用户是否有项目管理权限
        return projectService.hasProjectManagePermission(announcement.getProjectId(), userId);
    }

    @Override
    @Transactional(readOnly = true)
    public boolean hasAnnouncementViewPermission(Long announcementId, Long userId) {
        // 检查公告是否存在
        ProjectAnnouncement announcement = announcementRepository.findById(announcementId)
                .orElseThrow(() -> new BusinessException("公告不存在: " + announcementId));
        
        // 检查用户是否有项目查看权限
        return projectService.hasProjectViewPermission(announcement.getProjectId(), userId);
    }
}
